package com.yunbao.web.servlet;

import com.yunbao.ioc.annotation.Controller;
import com.yunbao.ioc.annotation.RequestMapping;
import com.yunbao.ioc.factory.BeanFactory;
import com.yunbao.ioc.utils.AnnotationUtils;
import com.yunbao.web.interceptor.HandlerInterceptor;
import com.yunbao.web.interceptor.HandlerInterceptorRegistry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Created by louisyuu on 2020/3/12 下午4:38
 */
public class RequestMappingHandlerMapping implements HandlerMapping {

    private BeanFactory beanFactory;

    private List<HandlerMethod> handlerMethods = new ArrayList<>();


    public RequestMappingHandlerMapping(List<String> controllerClassNames, BeanFactory beanFactory) {
        this.beanFactory = beanFactory;


        for (String className : controllerClassNames) {
            try {
                Class<?> aClass = Class.forName(className);

                if (AnnotationUtils.hasAnnotation(aClass, Controller.class)) {
                    StringBuilder baseUri = new StringBuilder();

                    if (aClass.isAnnotationPresent(RequestMapping.class)) {
                        baseUri = new StringBuilder(aClass.getAnnotation(RequestMapping.class).value());
                    }

                    Method[] methods = aClass.getDeclaredMethods();
                    for (Method method : methods) {
                        if (method.isAnnotationPresent(RequestMapping.class)) {
                            String uri = baseUri.append(method.getAnnotation(RequestMapping.class).value()).toString();
                            HandlerMethod handlerMethod = new HandlerMethod();
                            handlerMethod.setHandler(beanFactory.getBean(transferBeanName(aClass)));
                            handlerMethod.setHandlerMethod(method);
                            handlerMethod.setUriPattern(Pattern.compile(uri));

                            Parameter[] parameters = method.getParameters();
                            for (int i = 0; i < parameters.length; i++) {
                                Parameter parameter = parameters[i];
                                if (parameter.getType() == HttpServletRequest.class
                                        || parameter.getType() == HttpServletResponse.class) {
                                    // 如果是request和response对象，那么参数名称写HttpServletRequest和HttpServletResponse
                                    handlerMethod.getParameterMapping().put(parameter.getType().getSimpleName(), i);
                                } else {
                                    handlerMethod.getParameterMapping().put(parameters[i].getName(), i);
                                }

                            }
                            HandlerInterceptorRegistry.getInstance().registerHandlerInterceptors(handlerMethod, this.beanFactory.getBeans(HandlerInterceptor.class));
                            handlerMethods.add(handlerMethod);
                            if (aClass.isAnnotationPresent(RequestMapping.class)) {
                                baseUri = new StringBuilder(aClass.getAnnotation(RequestMapping.class).value());
                            }
                        }
                    }

                }

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }


        }

    }

    @Override
    public HandlerExecutionChain getHandler(HttpServletRequest request) {

        HandlerExecutionChain handlerExecutionChain = new HandlerExecutionChain();
        for (HandlerMethod handlerMethod : handlerMethods) {
            if (handlerMethod.getUriPattern().matcher(request.getRequestURI()).matches()) {
                handlerExecutionChain.setHandlerMethod(handlerMethod);
                handlerExecutionChain.setInterceptors(HandlerInterceptorRegistry.getInstance().getHandlerInterceptors(handlerMethod));
                return handlerExecutionChain;
            }
        }
        return handlerExecutionChain;
    }


    private String transferBeanName(Class clazz) {
        String classSimpleName = clazz.getSimpleName();
        String sub = classSimpleName.substring(1);
        String pre = classSimpleName.substring(0, 1);
        String beanId = pre.toLowerCase() + sub;
        return beanId;
    }
}
